using System;
using System.Collections.Generic;
using opt.Analysis.Branch;
using CLELCore.Assembly.CLELInstructions;

namespace opt.lib.BIR
{
	public class BIRVisitor : IBIRVisitor
	{
		private BranchOver _br_over;
		private bool[] _was_replaced;

		public BIRVisitor(BranchOver br_over,bool[] was_replaced)
		{
			_br_over = br_over;
			_was_replaced = was_replaced;
		}

		private int GetDiff(BranchKey key)
		{
			Int32 offset = _br_over.GetOffset(key);
			byte opcode = _br_over.GetOpcode(key);
			if(offset >= -128 && offset <= 127 && BranchUtilities.IsLongBranch(opcode))
			{
				//always return 3 becuase all long branches are 5 bytes
				// and all short branches are 2 bytes (5 - 2 = 3)
				return 3;
			}
			//do not replace, so return 0
			return 0;
		}

		public bool Visit(int index,BranchKey key)
		{
			List<BranchKey> over;
			int over_count;
			int diff = GetDiff(key);
			bool changed = false;
			int i,off;
			BranchKey over_key;
			if(diff > 0)
			{
				changed = true;
				_was_replaced[index] = true;
				//take diff off of each in over
				over = _br_over.GetBranchOvers(key);
				over_count = over.Count;
				for(i = 0;i < over_count;i++)
				{
					over_key = over[i];
					off = _br_over.GetOffset(over_key);
					if(off > 0)
						off = off - diff;
					else
						off = off + diff;
					_br_over.SetOffset(over_key,off);
				}
			}
			return changed;
		}
	}
}
